package com.zdw.demo.controller;

import com.zdw.common.parent.BasePage;
import com.zdw.common.parent.JSONResult;
import com.zdw.demo.config.international.InternationalUtils;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <p>
 * 内省机制 前端控制器
 * </p>
 *
 * @author 卓德文
 * @since 2023-05-18
 */
@RestController
@RequestMapping("/introspector")
public class IntrospectorController {

    /**
     * 内省机制(获取和操作对象中的属性)
     *
     * @return
     */
    @PostMapping("/introspectorTest")
    @ApiOperation("内省机制(获取和操作对象中的属性)")
    public JSONResult introspectorTest() {
        try {
            //1.获取字节码对象
            Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");


            //2.反射获取构造方法(使用Class类的方法),并调用构造方法(使用Construcor类的方法)
            Constructor<?> declaredConstructor = customerClass1.getDeclaredConstructor(String.class);
            Object instance = declaredConstructor.newInstance("卓德文");
            System.out.println("反射构造方法,实例类型:" + instance.getClass());


            //3.获取BeanInfo对象
            //3.1.获取指定字节码类型的BeanInfo对象
            BeanInfo beanInfo = Introspector.getBeanInfo(customerClass1);
            //3.2.获取指定字节码类型的BeanInfo对象,遇到某个父类时停止
            BeanInfo beanInfoStopClz = Introspector.getBeanInfo(customerClass1, BasePage.class);


            //4.获取属性描述器PropertyDescriptor
            PropertyDescriptor[] proDescriptors = beanInfo.getPropertyDescriptors();
            StringBuilder sb = new StringBuilder();
            for (PropertyDescriptor proDescriptor : proDescriptors) {
                sb.append(proDescriptor.getName()).append(";");
            }
            System.out.println("Bean中所有属性有:" + sb);


            //5.获取读写方法,并操作属性
            for (PropertyDescriptor proDescriptor : proDescriptors) {
                //5.1.找到对应的属性
                if (proDescriptor.getName().equals("name")) {
                    //5.2.Setter方法--writeMethod
                    Method writeMethod = proDescriptor.getWriteMethod();
                    //5.3.Getter方法--readMethod
                    Method readMethod = proDescriptor.getReadMethod();
                    //5.4.通过反射调用writeMethod方法,修改属性值
                    writeMethod.invoke(instance, "小茗同学");
                    //5.5.通过反射调用readMethod方法,读取属性值
                    Object readStr = readMethod.invoke(instance);
                    System.out.println("属性值为:" + readStr);
                    break;
                }
            }

        } catch (Exception e) {
            return new JSONResult().markSuccess(InternationalUtils.getInternational("common.fail"), null);
        }
        return new JSONResult().markSuccess(InternationalUtils.getInternational("common.success"), null);
    }

    //主方法测试
    public static void main(String[] args) throws ClassNotFoundException, IntrospectionException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取字节码对象
        Class<?> customerClass1 = Class.forName("com.zdw.demo.dto.CustomerSelectDto");


        //2.反射获取构造方法(使用Class类的方法),并调用构造方法(使用Construcor类的方法)
        Constructor<?> declaredConstructor = customerClass1.getDeclaredConstructor(String.class);
        Object instance = declaredConstructor.newInstance("卓德文");
        System.out.println("反射构造方法,实例类型:" + instance.getClass());


        //3.获取BeanInfo对象
        //3.1.获取指定字节码类型的BeanInfo对象
        BeanInfo beanInfo = Introspector.getBeanInfo(customerClass1);
        //3.2.获取指定字节码类型的BeanInfo对象,遇到某个父类时停止
        BeanInfo beanInfoStopClz = Introspector.getBeanInfo(customerClass1, BasePage.class);


        //4.获取属性描述器PropertyDescriptor
        PropertyDescriptor[] proDescriptors = beanInfo.getPropertyDescriptors();
        StringBuilder sb = new StringBuilder();
        for (PropertyDescriptor proDescriptor : proDescriptors) {
            sb.append(proDescriptor.getName()).append(";");
        }
        System.out.println("Bean中所有属性有:" + sb);


        //5.获取读写方法ReadMethod/WriteMethod,并操作属性
        for (PropertyDescriptor proDescriptor : proDescriptors) {
            //5.1.找到对应的属性
            if (proDescriptor.getName().equals("name")) {
                //5.2.Setter方法--writeMethod
                Method writeMethod = proDescriptor.getWriteMethod();
                //5.3.Getter方法--readMethod
                Method readMethod = proDescriptor.getReadMethod();
                //5.4.通过反射调用writeMethod方法,修改属性值
                writeMethod.invoke(instance, "小茗同学");
                //5.5.通过反射调用readMethod方法,读取属性值
                Object readStr = readMethod.invoke(instance);
                System.out.println("属性值为:" + readStr);
                break;
            }
        }
    }

}
